package serverService;

import domain.*;

import java.net.*;
import java.util.logging.Logger;
import java.io.*;

import serverExceptions.ParseException;

public class ClientSession extends Thread {
	static Logger logger = Logger
			.getLogger(ClientSession.class.getName());
	static int nextId;
	int SessionId;
	Socket clientSocket;
	PrintWriter out;
	BufferedReader in;

	public ClientSession(Socket clientSocket) {
		this.clientSocket = clientSocket;
		SessionId = nextId++;
	}

	public void run() {
		logger.info("new Client Session Started");

		init();
		String message;
		MessageType messType;
		do {
			try {
				logger.info("waiting for message");
				message = in.readLine();
				logger.info("Client > " + message);
				try {
					messType = MessageParser.getMessageType(message);
					switch (messType) {
					case LOGON:
						logonAction(message);
						break;
					case Logout:
						logoutAction(message);
						return;
					case NewOrderSingle:
						newOrderAction(message);
						break;
					}
				} catch (ParseException e) {
					e.printStackTrace();
				}

			} catch (IOException e) {
				StockExchangeServer.listOfClientSession.remove(this);
				return;
			}
		} while (true);
	}

	void sendStringMessage(final String msg) {
		Thread thread = new Thread(new Runnable() {
			public void run() {
				out.println(msg);
				out.flush();
				logger.info("server> " + msg);
			}
		});

		thread.start();

	}

	void sendResult(MatchResult result) {
		if (StockExchangeServer.listOfClientSession.get(result.getBuyerOrder()
				.getOwner().getName()) == this) {
			ClientMessage mess = new ClientMessage(result.getBuyerOrder());
			mess.setMessageType(MessageType.Execution_Report);
			mess.setOrdStatus(OrderStatus.FILLED);
			sendStringMessage(mess.toString());
		} else if (StockExchangeServer.listOfClientSession.get(result
				.getSellerOrder().getOwner().getName()) == this) {
			ClientMessage mess = new ClientMessage(result.getSellerOrder());
			mess.setMessageType(MessageType.Execution_Report);
			mess.setOrdStatus(OrderStatus.FILLED);
			sendStringMessage(mess.toString());
		}

	}

	public void init() {
		try {
			out = new PrintWriter(new OutputStreamWriter(
					clientSocket.getOutputStream()));
			in = new BufferedReader(new InputStreamReader(
					clientSocket.getInputStream()));
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	private void logonAction(String message) {
		String client;
		try {
			client = MessageParser.getSenderCompID(message);
			if (StockExchangeServer.listOfClientSession.containsKey(client)) {
				ClientMessage mess = new ClientMessage();
				mess.setMessageType(MessageType.Reject);
				mess.setSessionRejectReason(9);
				mess.setText("Session already exists");
				sendStringMessage(mess.toString());
			}
			logger.info("new client: " + client);
			ClientMessage mess = new ClientMessage();
			mess.setMessageType(MessageType.LOGON);
			mess.setSenderCompID(client);
			sendStringMessage(mess.toString());
			StockExchangeServer.listOfClientSession.put(client, this);
		} catch (ParseException e) {
			ClientMessage mess = new ClientMessage();
			mess.setMessageType(MessageType.Reject);
			mess.setSessionRejectReason(9);
			mess.setText("Parsing Error");
			sendStringMessage(mess.toString());
		}
	}

	private void logoutAction(String message) {
		String client;
		try {
			client = MessageParser.getSenderCompID(message);
			StockExchangeServer.listOfClientSession.remove(client);
		} catch (ParseException e) {
			ClientMessage mess = new ClientMessage();
			mess.setMessageType(MessageType.Reject);
			mess.setSessionRejectReason(9);
			mess.setText("Parsing Error");
			sendStringMessage(mess.toString());
		}
	}

	private void newOrderAction(String message) {
		String client;
		Stock stock;
		TypeOfOrder type;
		Order order = new Order();
		try {
			client = MessageParser.getSenderCompID(message);
			stock = MessageParser.getStock(message);
			type = MessageParser.getTypeOfOrder(message);
			ClientInfo clientInf = new ClientInfo(client);
			order.setAmount(MessageParser.getOrdQntity(message));
			order.setOwner(clientInf);
			order.setCliOrdID(MessageParser.getOrdID(message));
			order.setPrice(MessageParser.getPrice(message));
			order.setStock(stock);
			order.setType(type);
	//	Matcher.getMatcher().addOrder(order);
			order.setStatus(OrderStatus.NEW);
			ClientMessage mess = new ClientMessage(order);
			mess.setMessageType(MessageType.Execution_Report);
			mess.setOrdStatus(OrderStatus.NEW);
			mess.setStock(stock);
			mess.setSenderCompID(client);
			mess.setAmount(order.getAmount());
			mess.setPrice(order.getPrice());
			mess.setOrderType(order.getType());
			sendStringMessage(mess.toString());
			logger.info("New order added " + order.getStock() + " Amount: "
					+ order.getAmount()+" Price: "+order.getPrice());
			switch (type) {
			case BUY:
				Matcher.getMatcher().AddBuyer(order);
				break;
			case SELL:
				Matcher.getMatcher().AddSeller(order);
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}
	}
}
